package com.lollipop.programming.thread.productconsume;

import lombok.extern.slf4j.Slf4j;

import java.util.LinkedList;
import java.util.Queue;

/**
 * @Author Lollipop
 * @Date 2025/4/7 15:31
 * @Description 使用多线程实现生产者-消费者模型-[wait()和notify()方法]
 */
@Slf4j
public class ProducerConsumerV1 {
    private static final int MAX_CAPACITY = 5;
    // 生产总量限制
    private static final int TOTAL_ITEMS = 20;
    private final Queue<Integer> buffer = new LinkedList<>();
    // 专用锁对象
    private final Object lock = new Object();
    private volatile boolean isRunning = true;

    public static void main(String[] args) throws InterruptedException {
        ProducerConsumerV1 pc = new ProducerConsumerV1();

        Thread producer = new Thread(() -> {
            try {
                pc.produce();
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                log.error("生产者被中断", e);
            }
        }, "Producer");

        Thread consumer = new Thread(() -> {
            try {
                pc.consume();
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                log.error("消费者被中断", e);
            }
        }, "Consumer");

        producer.start();
        consumer.start();

        // 等待生产完成
        producer.join();
        // 发送停止信号
        pc.shutdown();
        consumer.join();

        log.info("==== 程序正常结束 ====");
    }

    public void produce() throws InterruptedException {
        for (int i = 0; i < TOTAL_ITEMS && isRunning; i++) {
            synchronized (lock) {
                while (buffer.size() == MAX_CAPACITY) {
                    lock.wait();
                }
                buffer.add(i);
                log.info("{} 生产: {} (库存: {})", Thread.currentThread().getName(), i, buffer.size());
                lock.notifyAll();
            }
            // 模拟生产耗时
            Thread.sleep(300);
        }
        log.info("--> 生产者完成");
    }

    public void consume() throws InterruptedException {
        while (isRunning || !buffer.isEmpty()) {
            synchronized (lock) {
                while (buffer.isEmpty() && isRunning) {
                    // 添加超时防止死等
                    lock.wait(500);
                }
                if (!buffer.isEmpty()) {
                    int value = buffer.poll();
                    log.info("{} 消费: {} (剩余: {})", Thread.currentThread().getName(), value, buffer.size());
                    lock.notifyAll();
                }
            }
            // 模拟消费耗时
            Thread.sleep(1000);
        }
        log.info("--> 消费者完成");
    }

    public void shutdown() {
        isRunning = false;
        synchronized (lock) {
            // 唤醒所有等待线程
            lock.notifyAll();
        }
    }
}
